As mentioned, SQL Server allows you to create
customized error messages and raise them inside your code. As a
database developer, you should create a set list of additional messages
for use by your application so you can reuse them inside your
programmable objects. Also, user-defined errors can significantly
improve readability of operations and problems that occur in your
application. Remember that these user-defined error messages help you
customize and standardize messages returned from the procedures,
functions, and other programmable objects in your database. This
feature also provides you with an efficient way to develop code with
the reuse of the same messages.
System Procedures and Parameters
User-defined error messages can be managed with the use of three system procedures: sp_addmessage, sp_altermessage, and sp_dropmessage. The sp_addmessage procedure lets you store a user-defined error message in an instance. Remember that these messages can be viewed using the sys.messages catalog view. The syntax of this procedure is as follows:
sp_addmessage [ @msgnum = ] msg_id, [ @severity = ] severity,
[ @msgtext = ] 'msg'
[, [ @lang = ] 'language' ]
[, [ @with_log = ] { 'TRUE' | 'FALSE' } ]
[, [ @replace = ] 'replace' ]
When you compare the syntax of this procedure with the structure of the sys.messages
catalog view, you can easily understand how to use it. The first
parameter is the message ID number. For user-defined error messages,
you can define an ID number as an integer between 50,001 and
2,147,483,647. As you saw in the sys.messages structure, the combination of this number and language must be unique. This parameter is mandatory.
The
second parameter is severity level. The severity value must be an
integer between 1 and 25. Keep in mind that you should choose the
severity level of this customized error message according to SQL Server
severity levels, easing maintenance, organization, and usability. This
parameter is also mandatory.
The last mandatory input parameter is the text of the error message. This parameter accepts text in NVARCHAR(255) and supports arguments passed by RAISERROR
statements. This ability to utilize arguments provides a flexible and
rich use of user-defined error messages, including ways to show
important information such as the login that executed the code that
raised the error message.
One of the most interesting parameters of the sp_addmessage
procedure is language. This optional input allows you to add the same
message in different languages. SQL Server offers support for 33
languages, whose information is stored in the sys.syslanguages
table. Languages supported by SQL Server include English (British and
American), Portuguese, Spanish, Italian, and Japanese. Because multiple
languages may be installed on the same server, this parameter specifies
the language in which the message is written. If you don’t inform the
input, the default language of the session is the assumed value of this
parameter.
If you need to create an error that must write to the Windows application log, the @with_log parameter is the key. This parameter accepts TRUE or FALSE values. If you inform TRUE, your error will always be written to the Windows application log. If you inform FALSE,
your user-defined error may still be written to the log depending on
how the error is raised. An important feature of this parameter is that
only members of the sysadmin
server role can use it. Also, when an error is written to the Windows
application log, it is also written to the Database Engine error log
file.
The last
parameter, replace, is used to update the message text, severity level,
and log option of an existing error message. An interesting feature
useful in multiple language environments is that when you replace a
U.S. English message, the severity level is replicated for all messages
in all other languages with the same ID number.
Another way to change the log option of a user-defined error is with the sp_altermessage
procedure. Contrary to what the name suggests, this procedure doesn’t
alter error messages: it just changes their log option value. The
syntax of this procedure is as follows:
sp_altermessage [ @message_id = ] message_number, 'WITH_LOG', { 'TRUE'
| 'FALSE' }
This procedure is a straightforward statement: you only need to inform the message ID number and the WITH_LOG parameter value, which can be TRUE
or FALSE. Like the WITH_LOG parameter in the sp_addmessage, this procedure can only be executed by members of the sysadmin server role.
You can drop a user-defined error using the sp_dropmessage procedure. The syntax of this procedure is as follows:
sp_dropmessage [ @msgnum = ] message_number
[, [ @lang = ] 'language' ]
By
default, you only need to inform the ID number of the error message you
want to drop. One cool thing about this procedure is the optional
language parameter. You can drop a language version of an error
message, while keeping the other languages versions intact. If you want
to drop all language versions of a message, you need to specify the ALL value for the language parameter.
As
a database developer, you should always document your database.
Documentation describes all aspects of your solution and provides
information that helps you manage, control, and update objects created
such as tables, procedures, and functions. Also, documentation is
essential for troubleshooting, since it gives you a history of your
database and the changes realized.
It
is especially convenient that your library of user-defined error
messages allows you to develop this documentation faster and with more
consistency.
|
Example: Creating User-Defined Error Messages
In
this example, we will create an error message in three languages and
see how to manage them in SQL Server. The first part is creating the
message in English, Portuguese, and Spanish using the sp_addmessage procedure. Figure 1 shows the syntax of this process.
Let’s take a better look at the code in the figure. You can see that we used the sp_addmessage
procedure three times, using the same error number but a different
language each time. Observe that the severity is the same for all three
procedures: the severity level of one language version of a particular
error message must be the same as the severity level of the other
language versions.
The next step is to see these messages stored inside SQL Server using the sys.messages catalog view. Figure 5.2 shows a SELECT statement that returns your new message and its language versions.
We used an INNER JOIN statement with the sys.syslanguages
system table to retrieve the language name, giving us a better look at
the result set. You can see that all three versions of the error
message are stored inside SQL Server with the same number and severity.
Also, this error message isn’t logged, as the is_event_logged column has the value 0.
Now we will change the severity value of this message from 5 to 7. Remember that sp_addmessage is also capable of making changes to the message using the @replace parameter. Figure 3
shows the code that executes the desired change and the appearance of
our error message inside SQL Server after the modification.
As
you’ve seen before, when you change the severity of the English version
of a message, this modification is replicated to the other language
versions of the same message. Now all versions have a severity level of
7.
Now, let’s say that you wish to log this error when it arises. You could use the sp_addmessage with the @replace parameter to change this property, but let’s use an easier way: the sp_altermessage procedure. Figure 4 shows the syntax of sp_altermessage and its result in SQL Server.
As you can see, all versions now have the is_event_logged column with the value 1, indicating that this error will log when it arises. Now, let’s finish this example using the sp_dropmessage procedure to remove this error. First, we will remove the Spanish version of this message. Figure 5 shows how to drop one version of your message.
You can see that the Spanish version was removed from the sys.messages catalog view. Now, we will remove all language versions of this error message using the ALL value for the @language parameter. See the result in SQL Server in Figure 6.
Raising User-Defined Error Messages
Once
your custom error messages are created, the next step is to understand
how to return them to applications and users when they are executing
your T-SQL codes. As mentioned before, SQL Server does not understand a
user-defined error as an error until you tell it to raise a custom
message as one. To manually raise a user-defined error message in SQL
Server, you must use a RAISERROR statement. The general syntax of this statement is as follows:
RAISERROR ( { msg_id | msg_str | @local_variable }
{,severity,state }
[,argument [,...n ] ] )
[ WITH option [,...n ] ]
The RAISERROR
statement is really easy to understand when you already know how to
manage user-defined error messages. The statement is divided in four parts,
plus a WITH clause. The first part is where you inform SQL Server which
error you want to raise. If the error message that you wish to raise is
already included in the sys.messages
catalog view, you only need to indicate its ID number. That’s why you
should standardize your messages and add them in SQL Server: you can
reuse them inside your programmable objects and transactions.
A RAISERROR
statement can also inform a customized text or a local variable of your
script that stores a text as the error message. The customized text can
have a maximum of 2,047 characters and the associated error number is
50000. If your message contains 2,048 or more characters, SQL Server
will only display the first 2,044, and three ellipsis points will
indicate that the message has been truncated.
Although the RAISERROR
statement allows you to customize text directly, the management of
these messages becomes difficult if you use the same message many times
across your database. Keep in mind that the best way to standardize,
control, and manage error messages is by using the sys.messages catalog view, and you, as the database developer, should always use this method.
|
One of the most interesting things that customized text supports is the use of arguments.
Arguments allow you to show important information, such as the database
that the user was connected to when he executed the code that raised
the error message. An argument can be a string or a value, and it’s
placed inside the customized text. The general syntax of an argument is
as follows:
% [[flag] [width] [. precision] [{h | l}]] type
The items between the percent symbol (%) and type are responsible for formatting the argument and are optional. The flag determines spacing and justification for your argument. Table 1 shows a list of flags supported by SQL Server:
Table 1. Flags Supported by SQL Server
Flag | Description |
---|
- (dash or minus sign) | Left-justify the argument value. Only makes a difference when you supply a fixed width. |
+ (plus sign) | Indicates the positive or negative nature if the parameter is a signed numeric type. |
0 (zero) | Tells SQL Server to pad the left side of a numeric value with zeros until the minimum width is reached. |
# (pound sign) | Tells
SQL Server to use the appropriate prefix (0 or 0x) depending on whether
it is octal or hexadecimal. Applies only to octal and hexadecimal
values. |
' ' (blank) | Pads the left of a numeric value with spaces if positive |
The width
part of an argument sets the amount of space you want to hold for the
argument value. This is an integer value. You can also specify an
asterisk (*) to let SQL Server automatically determine the width
according to the value you set for precision. The precision
part determines the maximum number of digits or characters that will be
outputted. For example, if a string has 10 characters and precision is
set at 5, only the first 5 characters of the string value are used. On
the other hand, the precision will be the minimum number of digits
printed if your argument is an integer. Following precision, you can
indicate if a value is an h ( shortint) or l ( longint) when the type parameter is set as an integer, octal, or hexadecimal value.
The last step is informing the value type for the argument. Table 2 shows the supported value types and their respective symbols.
Table 2. Argument Types Supported by SQL Server
Type of Argument | Symbol |
---|
Signed integer | d |
Unsigned integer | u |
String | s |
Unsigned octal | o |
Unsigned hexadecimal | x |
You can use a maximum of 20 arguments in a customized text. Their values are passed after the state part of the RAISERROR statement in the same sequence that they are placed inside the text. Arguments are also supported within the text of the sp_addmessage procedure, providing you great flexibility.
The next part of the RAISERROR statement is severity,
where you inform the severity level associated with your error message.
If you use the message ID number to raise your error, the severity
specified here will override the severity specified in the sys.messages
catalog view. Severity levels from 0 through 18 can be specified by any
user. However, severity levels from 19 through 25 can only be specified
by members of the sysadmin fixed server role. Also, messages with severity levels from 19 through 25 require logging.
After severity, the next part is to define the state
of the error. The state is an integer value from 0 through 255 that
helps you find the section of code raising the error, when same
user-defined error can rise at multiple locations. To accomplish this,
you only need to define a unique state number for each location that
can raise the message. The state part is really useful when you are
dealing with complex and long strings of code.
The argument
is the last part and it’s optional. Here you provide values for the
arguments defined in the text of your error message. The order of
argument values must correspond to their respective arguments as
defined in the text of the message. Remember that you can use 20
arguments at maximum. Each argument can be any of these data types: tinyint, smallint, int, char, varchar, nchar, nvarchar, binary, or varbinary. No other data types are supported.
Finally, the WITH clause makes three more options available: LOG, NOWAIT, and SETERROR. The LOG
option logs the raised error in the error log and the application log
for the instance. To use this option, the user executing the RAISERROR statement must be a member of the sysadmin fixed server role. The NOWAIT option forces the message to be delivered to the client immediately instead of waiting until everything
is done. This option is really useful when dealing with long reports
and debugging your code, since it displays all of the prints and
selects ahead of it.
The SETERROR option allows you to set the value of the @@ERROR function to be equal to the last error ID number raised. By default, a RAISERROR statement doesn’t set @@ERROR to the value of the error ID you raised. Instead, it reflects the success or failure of your actual RAISERROR statement. The SETERROR@@ERROR variable to equal the last error ID number raised. Look for more about @@ERROR later in this chapter. option overrides this and sets the value of the
Example: Raising Messages Using the RAISERROR Statement
In this example, we will raise some error messages using the RAISERROR statement and some options. First, let’s raise a basic custom text. Figure 7 shows the code of the RAISERROR statement and its return to the user.
Let’s
look at the return from SQL Server. First, it shows the text of the
error message raised. Then, it shows the error number of this message.
In this example, the error number is 50000 because we used a custom
text. Remember that when you raise a user-defined error stored in SQL
Server, the error ID number is from the message_id column of the sys.messages
catalog view. SQL Server also exhibits the severity level and the state
of the message. In this example, the severity level is 5 and the state
is 1.
Now, let’s raise a more complex error message using arguments. Figure 8 shows a RAISERROR statement with four interesting arguments and the return to the user.
Now,
your error message is more dynamic and informational. In the text of
the message, you defined four arguments: three strings (%s) and one unsigned integer (%u).
You can see that these arguments show the user some important
information such as the number of his process inside SQL Server. After
the message text, severity, and state, you inform the value of the four
arguments. The argument values must be in the same order as their
respective arguments in the text of the message. Also,
you can see that these arguments can be local variables of your script
or global variables and functions of your instance. This property gives
you great flexibility to develop your custom messages as your business
requires.
Now, let’s assume that your error message is so important that it must be logged. To log this error, you only need to add WITH LOG at the end of the RAISERRORWITH LOG and Figure 9 displays your error in the SQL Server log. statement. The following code shows how to use
--Retrieve the current login
DECLARE @LOGINNAME VARCHAR(50)
SELECT @LOGINNAME = ORIGINAL_LOGIN()
--A custom error message using arguments
RAISERROR ('This is a custom error message.
Login: %s,
Language: %s,
SPID: %u,
Server Name: %s', 5,1,
@LOGINNAME, @@LANGUAGE, @@SPID, @@SERVERNAME) WITH LOG
Although this RAISERROR
statement is great, you decide that this error message will be reused
many times inside your database. So, to standardize this error message,
you decide to use the sp_addmessage procedure and add it to SQL Server. Figure 10 shows the code to add the error message and the RAISERROR statement that raises it.
There is no need to indicate the text of the message and the log option in the RAISERROR statement. These were defined in the sp_addmessage procedure and will be retrieved at execution time. Also, observe that the RAISERROR
statement is much smaller when you use a previously defined error
message, easing the management of your code throughout your database.